#import "GPUImageUIElement.h"

@interface GPUImageUIElement ()
{
    UIView *view;
    CALayer *layer;
    
    CGSize previousLayerSizeInPixels;
    CMTime time;
    NSTimeInterval actualTimeOfLastUpdate;
}

@end

@implementation GPUImageUIElement

#pragma mark -
#pragma mark Initialization and teardown

- (id)initWithView:(UIView *)inputView;
{
    if (!(self = [super init]))
    {
		return nil;
    }
    
    view = inputView;
    layer = inputView.layer;

    previousLayerSizeInPixels = CGSizeZero;
    [self update];
    
    return self;
}

- (id)initWithLayer:(CALayer *)inputLayer;
{
    if (!(self = [super init]))
    {
		return nil;
    }
    
    view = nil;
    layer = inputLayer;

    previousLayerSizeInPixels = CGSizeZero;
    [self update];

    return self;
}


#pragma mark -
#pragma mark Layer management

- (CGSize)layerSizeInPixels;
{
    CGSize pointSize = layer.bounds.size;
    return CGSizeMake(layer.contentsScale * pointSize.width, layer.contentsScale * pointSize.height);
}

- (void)update;
{
    [self updateWithTimestamp:kCMTimeIndefinite];
}

- (void)updateUsingCurrentTime;
{
    if(CMTIME_IS_INVALID(time)) {
        time = CMTimeMakeWithSeconds(0, 600);
        actualTimeOfLastUpdate = [NSDate timeIntervalSinceReferenceDate];
    } else {
        NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
        NSTimeInterval diff = now - actualTimeOfLastUpdate;
        time = CMTimeAdd(time, CMTimeMakeWithSeconds(diff, 600));
        actualTimeOfLastUpdate = now;
    }

    [self updateWithTimestamp:time];
}

- (void)updateWithTimestamp:(CMTime)frameTime;
{
    [GPUImageContext useImageProcessingContext];

    CGSize layerPixelSize = [self layerSizeInPixels];
    CGFloat scale = 2;
    CGFloat layerPixelWidth = layerPixelSize.width * scale;
    CGFloat layerPixelHeight = layerPixelSize.height * scale;
    CGSize newLayerPixelSize = CGSizeMake(layerPixelWidth, layerPixelHeight);


    GLubyte *imageData = (GLubyte *) calloc(1, (int)layerPixelWidth * (int)layerPixelHeight * 4);

    CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
    CGContextRef imageContext = CGBitmapContextCreate(imageData,
                                                      (int)layerPixelWidth,
                                                      (int)layerPixelHeight,
                                                      8,
                                                      (int)layerPixelWidth * 4,
                                                      genericRGBColorspace,
                                                      kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
//    CGContextRotateCTM(imageContext, M_PI_2);
	CGContextTranslateCTM(imageContext, 0.0f, layerPixelHeight);
    CGContextScaleCTM(imageContext, layer.contentsScale * scale, -layer.contentsScale * scale);
    //        CGContextSetBlendMode(imageContext, kCGBlendModeCopy); // From Technical Q&A QA1708: http://developer.apple.com/library/ios/#qa/qa1708/_index.html

    [layer renderInContext:imageContext];

//    CGImageRef *cgImage = CGBitmapContextCreateImage(imageContext);
//    UIImage *image = [[UIImage alloc] initWithCGImage:cgImage];

    CGContextRelease(imageContext);
    CGColorSpaceRelease(genericRGBColorspace);

    // TODO: This may not work
    outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:newLayerPixelSize
                                                                             textureOptions:self.outputTextureOptions
                                                                                onlyTexture:YES];

    glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
    // no need to use self.outputTextureOptions here, we always need these texture options
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)layerPixelWidth, (int)layerPixelHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);

    free(imageData);
    
    for (id<GPUImageInput> currentTarget in targets)
    {
        if (currentTarget != self.targetToIgnoreForUpdates)
        {
            NSInteger indexOfObject = [targets indexOfObject:currentTarget];
            NSInteger textureIndexOfTarget = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];

            [currentTarget setInputSize:newLayerPixelSize atIndex:textureIndexOfTarget];
            [currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndexOfTarget];
        }
    }
//    for (id<GPUImageInput> currentTarget in targets)
//    {
//        if (currentTarget != self.targetToIgnoreForUpdates)
//        {
//            NSInteger indexOfObject = [targets indexOfObject:currentTarget];
//            NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
//            [currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndex];
//        }
//    }
}

@end
